#include "MongooseMgr.h"
#include <sstream>

#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif



MongooseMngr* MongooseMngr::m_oInstance = NULL;
std::once_flag MongooseMngr::m_flag;

static const char* s_root_dir = "./";
MongooseMngr* MongooseMngr::GetInstance()
{
	//return &(EventLoopMngr::m_oInstance);
	std::call_once(m_flag, [&](){
		MongooseMngr::m_oInstance = new MongooseMngr();
		//printf("\n *********** ########## EventLoopMngr::GetInstance call_once \n");

	});
	if (MongooseMngr::m_oInstance)
	{
		return MongooseMngr::m_oInstance;
	}
	return NULL;
}

MongooseMngr::MongooseMngr()
{

}
MongooseMngr::~MongooseMngr()
{

}


static void SetThreadName(std::string threadName, std::thread * loopThread)
{
#ifdef WIN32

	int wcharCount = MultiByteToWideChar(CP_UTF8, 0, threadName.c_str(), -1, NULL, 0);
	std::wstring wideString(wcharCount, L'\0');
	MultiByteToWideChar(CP_UTF8, 0, threadName.c_str(), -1, &wideString[0], wcharCount);

	PCWSTR pwstr = wideString.c_str();
	HRESULT hr = SetThreadDescription(loopThread->native_handle(), pwstr);
	if (FAILED(hr))
	{
		// Call failed.
		//MEDIA_TRACE_LOG("EventLoop", LL_ERROR, "*** TaskScheduler::SetThreadName error this:%p ", this);
	}
#else
	pthread_setname_np(loopThread->native_handle(), threadName.c_str());
#endif
}

std::string MongooseMngr::GetLocalAddr()
{
	std::string ip = get_local_ip();
	std::string ret = ip + ":" + std::to_string(m_port);
	return ret;

}
int32_t MongooseMngr::Init(std::string exposeDir, std::string ip, uint16_t port , std::string name_thread)
{
	std::lock_guard<std::mutex> locker(mutex_);
	if (connection_)
	{
		return 0;
	}
	m_port = port;
	m_exposeDir = exposeDir;
	//MEDIA_TRACE_LOG("MongooseMngr", LL_INFO, "### MongooseMngr::Init start ip:%s port:%d this:%p ",ip.c_str(), port,  this);
	std::string url = "http://" + ip + ":" + std::to_string(port);

	mg_mgr_init(&mgr_);
	connection_ = mg_http_listen(&mgr_, url.c_str(), MongooseMngr::OnEvent, this);
	if (!connection_) {
		return false;
	}

	poll_thread_.reset(new std::thread([this] {

		while (connection_) {
			mg_mgr_poll(&mgr_, 50);
		}

		}));

	SetThreadName(name_thread, poll_thread_.get());
	m_oCacheVec.resize(1024 * 1024 * 64);

	//MEDIA_TRACE_LOG("EventLoop", LL_INFO, "### MongooseMngr::Init end this:%p ", this);
	return 0;
}


#include "mongoose.h"
#include <stdio.h>
#include <sys/stat.h>

#define UPLOAD_DIR "./"  // 上传目录

// 创建目录（如果不存在）
static void create_upload_dir(void) {
	struct stat st = { 0 };
	if (stat(UPLOAD_DIR, &st) == -1) mkdir(UPLOAD_DIR, 0700);
}

// HTTP事件处理函数
static void upload(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
	if (ev == MG_EV_HTTP_MSG) {
		struct mg_http_message* hm = (struct mg_http_message*)ev_data;

		// 处理文件上传请求 (POST /upload)
		if (mg_match(hm->uri, mg_str("/upload"), NULL) && mg_strcmp(hm->method, mg_str("POST")) == 0) {
			// 检查Content-Type是否为multipart/form-data
			struct mg_str* ct = mg_http_get_header(hm, "Content-Type");
			if (ct == NULL || mg_strcasecmp(*ct, mg_str("multipart/form-data")) == NULL) {
				mg_http_reply(c, 400, "", "Invalid Content-Type");
				return;
			}

			// 解析multipart数据
			struct mg_http_part part;
			size_t offset = 0;
			while (mg_http_next_multipart(hm->body, offset, &part)) {
				// 检查是否为文件字段（字段名为"file"）
				if (mg_strcmp(part.name, mg_str("file")) == 0 && part.filename.buf != NULL) {
					// 生成保存路径
					char path[256];
					snprintf(path, sizeof(path), "%s%.*s", UPLOAD_DIR, (int)part.filename.len, part.filename.buf);

					// 保存文件到磁盘
					FILE* fp = fopen(path, "wb");
					if (fp != NULL) {
						fwrite(part.body.buf, 1, part.body.len, fp);
						fclose(fp);
						mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{\"status\":\"OK\"}");
					}
					else {
						mg_http_reply(c, 500, "", "Failed to save file");
					}
					return;
				}
				offset = part.body.buf - hm->body.buf + part.body.len;
			}
			mg_http_reply(c, 400, "", "No file uploaded");
		}
	}
}


void MongooseMngr::HandleHttpEvent(struct mg_connection* c, void* ev_data, void* user_data)
{
	printf("HandleHttpEvent \n");
	struct mg_http_message* hm = (struct mg_http_message*)ev_data;
	// 其他请求
	if (mg_match(hm->uri, mg_str("/api/hello"), NULL))
	{
		printf("HandleHttpEvent api/hello  \n");

		mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
		mg_http_printf_chunk(c, "ID PROTO TYPE      LOCAL           REMOTE \n");
		/*	for (struct mg_connection* t = connection->mgr->conns; t != NULL; t = t->next) {
				mg_http_printf_chunk(connection, "%-3lu %4s %s %M %M\n", t->id,
					t->is_udp ? "UDP" : "TCP",
					t->is_listening ? "LISTENING"
					: t->is_accepted ? "ACCEPTED "
					: "CONNECTED",
					mg_print_ip, &t->loc, mg_print_ip, &t->rem);
			}*/
		mg_http_printf_chunk(c, "");  // Don't forget the last empty chunk

		// --- 开启CORS
		/*mg_printf(connection, "HTTP/1.1 200 OK\r\n"
				  "Content-Type: text/plain\n"
				  "Cache-Control: no-cache\n"
				  "Content-Length: %d\n"
				  "Access-Control-Allow-Origin: *\n\n"
				  "%s\n", rsp.length(), rsp.c_str()); */
	}
	else if (mg_match(hm->uri, mg_str("/video"), NULL))
	{
		//VideoInfo(c);
	}
	else if (mg_match(hm->uri, mg_str("/api/sum"), NULL))
	{
		// 简单post请求，加法运算测试

		char n1[100], n2[100];
		double result;
		/* Get form variables */
		mg_http_get_var(&hm->body, "n1", n1, sizeof(n1));
		mg_http_get_var(&hm->body, "n2", n2, sizeof(n2));

		/* Compute the result and send it back as a JSON object */
		result = strtod(n1, NULL) + strtod(n2, NULL);
		//mg_printf_http_chunk(connection, "{ \"result\": %s }", rsp.c_str());

		std::string ret = "{\"result\":" + std::to_string(result) + "}";
		mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
		mg_http_printf_chunk(c, "%s\n", ret.c_str());

		mg_http_printf_chunk(c, "");

	}
	else if (mg_match(hm->uri, mg_str("/api/f2/*"), NULL)) {
		mg_http_reply(c, 200, "", "{\"result\": \"%.*s\"}\n", (int)hm->uri.len,
			hm->uri);
	}
	// 处理文件上传请求 (POST /upload)
	else if(mg_match(hm->uri, mg_str("/upload"), NULL)) {


		mg_http_upload(c, hm, &mg_fs_posix, "./tmp", 1024*1024*1024);

		mg_http_reply(c, 200, "", "Thank you! \n");
	}
	else {
		//struct mg_http_serve_opts opts = { .root_dir = s_root_dir };
		//mg_http_serve_dir(c, ev_data, &opts);

		printf("HandleHttpEvent / \n");
		struct mg_http_serve_opts opts = { 0 };
		opts.root_dir = m_exposeDir.c_str();
		//opts.ssi_pattern = s_ssi_pattern;

		if (mg_match(hm->uri, mg_str("/*.log"), NULL))
		{
			opts.extra_headers = "Content-Disposition: attachment\r\n";  // 强制下载头
		}
		else
		{
			opts.extra_headers = "";
		}

		mg_http_serve_dir(c, hm, &opts);
	}

	MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.buf,
		hm->uri.len, hm->uri.buf, hm->body.len, 3, c->send.buf + 9,
		c->send.len));

}
void MongooseMngr::OnEvent(struct mg_connection* conn, int ev, void* ev_data)
{

	MongooseMngr* server = reinterpret_cast<MongooseMngr*>(conn->fn_data);
	if (!server) {
		return;
	}

	if (ev == MG_EV_WS_MSG) {
		// Got websocket frame.
		//server->DoWsMeg(conn, ev_data, conn->fn_data);

	}
	else if (ev == MG_EV_WS_OPEN)
	{
		printf("MG_EV_WS_OPEN #### \n");
	}
	else if (ev == MG_EV_HTTP_MSG) {
		struct mg_http_message* hm = (struct mg_http_message*)ev_data;
		if (mg_match(hm->uri, mg_str("/websocket"), NULL)) {
			// Upgrade to websocket
			mg_ws_upgrade(conn, hm, NULL);

		}
		else
		{
			server->HandleHttpEvent(conn, ev_data, conn->fn_data);
		}
	}
	else if (ev == MG_EV_ACCEPT) {

	}
	else if (ev == MG_EV_CLOSE) {
		//server->p2p_sessios_.erase(conn);
		printf("MG_EV_CLOSE connected ... \n");
	}
}




#include <string>
#include <cstring>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

std::string get_local_ip() {
	std::string ip_address = "127.0.0.1"; // 默认返回回环地址
	 // 初始化Winsock（新增关键步骤）
#ifdef WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		return ip_address;
	}

	ULONG size = 0;
	DWORD result = GetAdaptersAddresses(AF_INET, 0, nullptr, nullptr, &size);

	if (result == ERROR_BUFFER_OVERFLOW) {
		PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES)malloc(size);
		if (addresses) {
			result = GetAdaptersAddresses(AF_INET, 0, nullptr, addresses, &size); // 参数4修正
			if (result == ERROR_SUCCESS) {
				for (PIP_ADAPTER_ADDRESSES addr = addresses; addr != nullptr; addr = addr->Next) {
					if (addr->OperStatus == IfOperStatusUp &&
						(addr->IfType == IF_TYPE_ETHERNET_CSMACD ||
							addr->IfType == IF_TYPE_IEEE80211)) {
						PIP_ADAPTER_UNICAST_ADDRESS ua = addr->FirstUnicastAddress;
						if (ua != nullptr) {
							sockaddr_in* sin = (sockaddr_in*)ua->Address.lpSockaddr;
							char buffer[INET_ADDRSTRLEN];
							inet_ntop(AF_INET, &sin->sin_addr, buffer, sizeof(buffer));
							if (strcmp(buffer, "127.0.0.1") != 0) {
								ip_address = buffer;
								break;
							}
						}
					}
				}
			}
			free(addresses);
		}
	}
	WSACleanup(); // 清理Winsock
	return ip_address;
#else
	struct ifaddrs* ifaddr = nullptr;
	if (getifaddrs(&ifaddr) == -1) {
		return ip_address;
	}

	for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
		if (!ifa->ifa_addr) {
			continue;
		}

		void* tmp_addr = nullptr;
		if (ifa->ifa_addr->sa_family == AF_INET) { // IPv4
			tmp_addr = &(reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr)->sin_addr);
			char buffer[INET_ADDRSTRLEN] = { 0 };
			inet_ntop(AF_INET, tmp_addr, buffer, INET_ADDRSTRLEN);
			if (strcmp(buffer, "127.0.0.1") != 0) {
				ip_address = buffer;
				break;
			}
		}
	}

	freeifaddrs(ifaddr);
#endif

	return ip_address;
}
